#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <stdbool.h>
#include <dlfcn.h>

#include "engine.h"
#include <glog/logging.h>

static void* g_handle = NULL;
static engine_t engine;

bool load_engine(const char *soname, int argc, char** argv) 
{
	if(g_handle){
		dlclose(g_handle);
		g_handle = NULL;
	}
	g_handle = dlopen(soname, RTLD_NOW | RTLD_LOCAL);
	if (NULL == g_handle) {
		LOG(ERROR) << "Failed to open library";
		return false;
	}

	void *init = dlsym(g_handle, "init");
	if (NULL == init) {
		LOG(ERROR) << "Failed to load init";
		return false;
	}

	void *uninit = dlsym(g_handle, "uninit");
	if (NULL == uninit) {
		LOG(ERROR) << "Failed to load uinit";
		return false;
	}

	void *process_sync = dlsym(g_handle, "process_sync");
	if (NULL == process_sync) {
		LOG(ERROR) << "Failed to load process_sync";
		return false;
	}

	void *process_async = dlsym(g_handle, "process_async");
	if (NULL == process_async) {
		LOG(ERROR) << "Failed to load process_async";
		return false;
	}

	engine.init = (bool (*)(int, char**))init;
	engine.uninit = (void (*)())uninit;
	engine.process_sync = (uint8_t *(*)(_pool_t*, const void*, size_t, request_t*, size_t*))process_sync;
	engine.process_async = (void (*)(_pool_t*, const void*, size_t, finish_callback, void*))process_async;

	if (!engine.init(argc, argv)){
		LOG(ERROR)<<"engine init error";
		return false;
	}

	return true;
}

void unload_engine()
{
	engine.uninit();
	if(g_handle){
		dlclose(g_handle);
		g_handle = NULL;
	}
}

uint8_t* process_sync(_pool_t* pool, 
		const void* data, 
		size_t data_len,
		struct request_tag* request, 
		size_t* output_len) 
{
	return engine.process_sync(pool, data, data_len, request, output_len);
}

void process_async(_pool_t* pool,
		void* data, 
		size_t data_len, 
		finish_callback callback,
		void* user_ptr)
{
	engine.process_async(pool, data, data_len, callback, user_ptr);
}
